﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MattDotson.GlobalToolkit.Diagnostics;

namespace MattDotson.GlobalToolkit
{
    /// <summary>
    /// A currency converter which uses the lastest exchange rate to convert
    /// </summary>
    public sealed class CurrentRateCurrencyConverter : ICurrencyConverter
    {
        /// <summary>
        /// Gets the current exchange rate.
        /// </summary>
        /// <param name="fromCurrencyCode">From currency code.</param>
        /// <param name="toCurrencyCode">To currency code.</param>
        /// <returns></returns>
        private static ExchangeRate GetCurrentExchangeRate(string fromCurrencyCode, string toCurrencyCode)
        {
            var exchangeRates = GlobalToolkitContext.ServiceLocator.Resolve<ICurrencyExchangeRateProvider>();
            if (null == exchangeRates)
            {
                //no exchange rate provider configured
                //TODO: add resource string
                throw new CurrencyConversionException();
            }

            return exchangeRates.GetLatestExchangeRate(fromCurrencyCode, toCurrencyCode);
        }

        #region ICurrencyConverter Members

        /// <summary>
        /// Determines whether this instance can convert the specified iso code A.
        /// </summary>
        /// <param name="fromCurrency">The currency to convert from.</param>
        /// <param name="toCurrency">The currency to convert to.</param>
        /// <returns>
        /// 	<c>true</c> if this instance can convert the specified currencies; otherwise, <c>false</c>.
        /// </returns>
        public bool CanConvert(CurrencyInfo fromCurrency, CurrencyInfo toCurrency)
        {
            Guard.NotNull("fromCurrency", fromCurrency);
            Guard.NotNull("toCurrency", toCurrency);

            return (null != GetCurrentExchangeRate(fromCurrency.IsoCurrencyCode, toCurrency.IsoCurrencyCode));
        }

        /// <summary>
        /// Converts the specified from.
        /// </summary>
        /// <param name="from">From.</param>
        /// <param name="toCurrency">To currency.</param>
        /// <returns></returns>
        public Currency Convert(Currency from, CurrencyInfo toCurrency)
        {
            Guard.NotNull("toCurrency", toCurrency);

            if (Currency.Empty == from)
            {
                return Currency.Empty;
            }

            ExchangeRate exchangeRate = GetCurrentExchangeRate(from.CurrencyInfo.IsoCurrencyCode, toCurrency.IsoCurrencyCode);
            if (null == exchangeRate)
            {
                //no exchange rate available
                //todo: resource for exception
                throw new CurrencyConversionException();
            }

            //TODO: decide what to do about divide by zero.
            decimal convertedValue = from.Value / new decimal(exchangeRate.Rate);

            Currency returnValue = new Currency(convertedValue, toCurrency);

            TraceSources.CurrencyTraceSource.TraceInformation(
                "Converted '{0}' to '{1}' using exchange rate of '{2}' as of {3}", 
                from, returnValue, exchangeRate.Rate, exchangeRate.AsOf);

            return returnValue;
        }

        #endregion
    }
}
